'use client';

/**
 * 权限树组件
 * - 按权限组（resource）分组展示
 * - 支持搜索、全选/反选、父子联动
 * - 通过 onChange 回调返回勾选的权限 ID 列表
 */

import React from 'react';
import { ChevronDown, Search } from 'lucide-react';
import { Checkbox } from '@/components/ui/checkbox';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';

function PermissionTree({
  data = [],
  value = [],
  onChange,
  className,
  searchable = true,
  defaultExpandAll = true,
  disabledPermissions = [],
  renderDescription,
}) {
  const [searchKeyword, setSearchKeyword] = React.useState('');
  const [expandedGroups, setExpandedGroups] = React.useState(() => {
    if (!defaultExpandAll) {
      return new Set();
    }
    return new Set(data.map((group) => group.group));
  });

  const disabledSet = React.useMemo(
    () => new Set(disabledPermissions),
    [disabledPermissions],
  );

  const selectedSet = React.useMemo(() => new Set(value), [value]);

  const normalizedData = React.useMemo(() => {
    if (!searchKeyword.trim()) {
      return data;
    }
    const keyword = searchKeyword.trim().toLowerCase();
    return data
      .map((group) => {
        const matchesGroup = group.group
          ?.toLowerCase()
          .includes(keyword);
        const permissions = (group.permissions ?? []).filter((item) => {
          const label =
            item.displayName || item.name || String(item.id);
          const description = item.description || '';
          const keywords = `${label} ${description}`.toLowerCase();
          return (
            matchesGroup ||
            keywords.includes(keyword) ||
            item.name?.toLowerCase().includes(keyword)
          );
        });
        if (!matchesGroup && permissions.length === 0) {
          return null;
        }
        return {
          ...group,
          permissions,
        };
      })
      .filter(Boolean);
  }, [data, searchKeyword]);

  const triggerChange = React.useCallback(
    (nextSet) => {
      onChange?.(Array.from(nextSet));
    },
    [onChange],
  );

  const handlePermissionToggle = React.useCallback(
    (permissionId, checked) => {
      const nextSet = new Set(selectedSet);
      const shouldAdd = checked === true || checked === 'indeterminate';
      if (shouldAdd) {
        nextSet.add(permissionId);
      } else {
        nextSet.delete(permissionId);
      }
      triggerChange(nextSet);
    },
    [selectedSet, triggerChange],
  );

  const handleGroupToggle = React.useCallback(
    (permissionIds, checked) => {
      const nextSet = new Set(selectedSet);
      const shouldAdd = checked === true || checked === 'indeterminate';
      permissionIds.forEach((id) => {
        if (shouldAdd) {
          nextSet.add(id);
        } else {
          nextSet.delete(id);
        }
      });
      triggerChange(nextSet);
    },
    [selectedSet, triggerChange],
  );

  const toggleExpand = React.useCallback((groupKey) => {
    setExpandedGroups((prev) => {
      const next = new Set(prev);
      if (next.has(groupKey)) {
        next.delete(groupKey);
      } else {
        next.add(groupKey);
      }
      return next;
    });
  }, []);

  return (
    <div className={cn('space-y-3', className)}>
      {searchable && (
        <div className="relative">
          <Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
          <Input
            placeholder="搜索权限名称 / 标识 / 描述"
            value={searchKeyword}
            onChange={(event) => setSearchKeyword(event.target.value)}
            className="pl-10"
          />
        </div>
      )}

      <div className="space-y-3">
        {normalizedData.length === 0 ? (
          <div className="rounded-lg border border-dashed border-muted-foreground/30 bg-muted/10 px-4 py-6 text-center text-sm text-muted-foreground">
            未找到匹配的权限，请尝试调整搜索关键字。
          </div>
        ) : (
          normalizedData.map((group) => {
            const permissions = group.permissions ?? [];
            const permissionIds = permissions.map((item) => item.id);
            const selectedCount = permissionIds.filter((id) =>
              selectedSet.has(id),
            ).length;
            const allSelected =
              permissionIds.length > 0 &&
              selectedCount === permissionIds.length;
            const isIndeterminate =
              selectedCount > 0 && selectedCount < permissionIds.length;
            const isExpanded = expandedGroups.has(group.group);

            return (
              <div
                key={group.group || 'unknown-group'}
                className="overflow-hidden rounded-lg border bg-card"
              >
                <div className="flex items-center justify-between gap-3 border-b bg-muted/40 px-4 py-3">
                  <div className="flex min-w-0 items-center gap-3">
                    <Checkbox
                      checked={
                        allSelected
                          ? true
                          : isIndeterminate
                            ? 'indeterminate'
                            : false
                      }
                      onCheckedChange={(nextChecked) =>
                        handleGroupToggle(permissionIds, nextChecked)
                      }
                      disabled={permissionIds.length === 0}
                    />
                    <div className="min-w-0">
                      <div className="truncate text-sm font-medium">
                        {group.group ?? '未分组权限'}
                      </div>
                      {group.description ? (
                        <div className="truncate text-xs text-muted-foreground">
                          {group.description}
                        </div>
                      ) : null}
                    </div>
                  </div>
                  <div className="flex items-center gap-2">
                    <Badge variant="outline" className="text-xs font-normal">
                      {selectedCount} / {permissionIds.length}
                    </Badge>
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      onClick={() => toggleExpand(group.group)}
                      className="size-7"
                    >
                      <ChevronDown
                        className={cn(
                          'size-4 transition-transform',
                          isExpanded ? 'rotate-0' : '-rotate-90',
                        )}
                      />
                    </Button>
                  </div>
                </div>

                {isExpanded && (
                  <div className="space-y-2 px-5 py-4">
                    {permissions.length === 0 ? (
                      <div className="rounded-md border border-dashed border-muted px-3 py-6 text-center text-xs text-muted-foreground">
                        该分组暂无权限。
                      </div>
                    ) : (
                      permissions.map((permission) => {
                        const permissionChecked = selectedSet.has(
                          permission.id,
                        );
                        const disabled = disabledSet.has(permission.id);
                        return (
                          <label
                            key={permission.id}
                            className={cn(
                              'flex cursor-pointer items-start gap-3 rounded-md px-2 py-1.5 text-sm transition hover:bg-muted/40',
                              disabled && 'cursor-not-allowed opacity-60',
                            )}
                          >
                            <Checkbox
                              checked={permissionChecked}
                              onCheckedChange={(nextChecked) =>
                                handlePermissionToggle(
                                  permission.id,
                                  nextChecked,
                                )
                              }
                              disabled={disabled}
                            />
                            <div className="flex flex-col gap-0.5">
                              <span className="font-medium leading-none">
                                {permission.displayName ||
                                  permission.name ||
                                  permission.id}
                              </span>
                              <span className="text-xs text-muted-foreground">
                                {permission.name}
                              </span>
                              {renderDescription
                                ? renderDescription(permission)
                                : permission.description && (
                                    <span className="text-xs text-muted-foreground">
                                      {permission.description}
                                    </span>
                                  )}
                            </div>
                          </label>
                        );
                      })
                    )}
                  </div>
                )}
              </div>
            );
          })
        )}
      </div>
    </div>
  );
}

export { PermissionTree };


